home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / fslcl / fslclNameHash.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  12.6 KB  |  487 lines

  1. /* fslclNameHash.c --
  2.  *
  3.  *      This is a modified version of the hashing utilities used for the
  4.  *      filesystem name cache.  The main difference is that there is a two
  5.  *      part key, the string and a file identifier. Also, entries are kept
  6.  *      in LRU order (in another list) for replacement when the table is
  7.  *      full.
  8.  *
  9.  * Copyright (C) 1983 Regents of the University of California
  10.  * All rights reserved.
  11.  */
  12.  
  13. #ifndef lint
  14. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/fslcl/fslclNameHash.c,v 9.4 90/10/08 15:38:49 mendel Exp $ SPRITE (Berkeley)";
  15. #endif  not lint
  16.  
  17. #include <sprite.h>
  18. #include <fs.h>
  19. #include <fsutil.h>
  20. #include <fslclNameHash.h>
  21. #include <fslcl.h>
  22. #include <fsStat.h>
  23. #include <string.h>
  24. #include <list.h>
  25. #include <sys.h>
  26.  
  27. #include <stdio.h>
  28.  
  29. static    Sync_Lock nameHashLock = Sync_LockInitStatic("Fs:nameHashLock");
  30. #define    LOCKPTR    &nameHashLock
  31.  
  32. static void HashInit _ARGS_((FslclHashTable *table, int numBuckets));
  33. static int Hash _ARGS_((FslclHashTable *table, char *string, 
  34.             Fs_HandleHeader *keyHdrPtr));
  35. static FslclHashEntry *ChainSearch _ARGS_((FslclHashTable *table, char *string,
  36.             Fs_HandleHeader *keyHdrPtr,  List_Links *hashList));
  37.  
  38.  
  39. /*
  40.  *---------------------------------------------------------
  41.  * 
  42.  * HashInit --
  43.  *
  44.  *    This routine just sets up the hash table with the given size.
  45.  *
  46.  * Results:    
  47.  *    None.
  48.  *
  49.  * Side Effects:
  50.  *    Memory is allocated for the initial bucket area.
  51.  *
  52.  *---------------------------------------------------------
  53.  */
  54.  
  55. static void
  56. HashInit(table, numBuckets)
  57.     register FslclHashTable    *table;
  58.     int            numBuckets;    /* How many buckets to create for 
  59.                      * starters. This number is rounded up 
  60.                      * to a power of two. */
  61. {
  62.     register    int         i;
  63.     register    FslclHashBucket     *tablePtr;
  64.  
  65.     /* 
  66.      * Round up the size to a power of two, and compute a shift and mask
  67.      * used to index into the hash header table.
  68.      */
  69.  
  70.     if (numBuckets < 0) {
  71.     numBuckets = -numBuckets;
  72.     }
  73.     table->numEntries = 0;
  74.     table->size = 2;
  75.     table->mask = 1;
  76.     table->downShift = 29;
  77.     while (table->size < numBuckets) {
  78.     table->size <<= 1;
  79.     table->mask = (table->mask << 1) + 1;
  80.     table->downShift--;
  81.     }
  82.  
  83.     fs_Stats.nameCache.size = table->size;
  84.  
  85.     List_Init(&(table->lruList));
  86.     table->table =
  87.     (FslclHashBucket *) malloc(sizeof(FslclHashBucket) * table->size);
  88.     for (i=0, tablePtr = table->table; i < table->size; i++, tablePtr++) {
  89.     List_Init(&(tablePtr->list));
  90.     }
  91. }
  92.  
  93. /*
  94.  *----------------------------------------------------------------------
  95.  *
  96.  * Fslcl_NameHashInit --
  97.  *
  98.  *    Make sure the local name hash table is initialized.  Called
  99.  *    when disks are attached so that diskless clients don't allocate
  100.  *    space for the name hash table.
  101.  *
  102.  * Results:
  103.  *    None.
  104.  *
  105.  * Side effects:
  106.  *    HashInit is called which allocates memory for the initial bucket area.
  107.  *    
  108.  *
  109.  *----------------------------------------------------------------------
  110.  */
  111.  
  112. void
  113. Fslcl_NameHashInit()
  114. {
  115.     if (fslclNameTablePtr == (FslclHashTable *)NIL) {
  116.     fslclNameTablePtr = &fslclNameTable;
  117.     HashInit(fslclNameTablePtr, fslclNameHashSize);
  118.     }
  119. }
  120.  
  121.  
  122. /*
  123.  *---------------------------------------------------------
  124.  *
  125.  * Hash --
  126.  *    This is a local procedure to compute a hash table
  127.  *    bucket address based on a pair <string, fileHdrPtr>.
  128.  *    The file information needs to be used to randomize the same
  129.  *    names found in different directories.
  130.  *
  131.  * Results:
  132.  *    The return value is an integer between 0 and size - 1.
  133.  *
  134.  * Side Effects:    
  135.  *    None.
  136.  *
  137.  * Note:
  138.  *    The randomizing code is stolen straight from the rand library routine.
  139.  *
  140.  *---------------------------------------------------------
  141.  */
  142.  
  143. INTERNAL static int
  144. Hash(table, string, keyHdrPtr)
  145.     register FslclHashTable *table;    /* The hash table (per domain?) */
  146.     register char     *string;    /* Name of the component */
  147.     Fs_HandleHeader    *keyHdrPtr;    /* Handle of the parent directory */
  148. {
  149.     register int     i = 0;
  150.  
  151.     while (*string != 0) {
  152.     i = i * 10 + *string++;
  153.     }
  154.     i += (int) keyHdrPtr;
  155.     return(((i*1103515245 + 12345) >> table->downShift) & table->mask);
  156. }
  157.  
  158.  
  159. /*
  160.  *---------------------------------------------------------
  161.  *
  162.  * ChainSearch --
  163.  *
  164.  *     Search the hash table for the entry in the hash chain.
  165.  *
  166.  * Results:
  167.  *    Pointer to entry in hash chain, NIL if none found.
  168.  *
  169.  * Side Effects:
  170.  *    None.
  171.  *
  172.  *---------------------------------------------------------
  173.  */
  174.  
  175. INTERNAL static FslclHashEntry *
  176. ChainSearch(table, string, keyHdrPtr, hashList)
  177.     FslclHashTable         *table;        /* Hash table to search. */
  178.     register char        *string;    /* Hash key, part 1 */
  179.     register Fs_HandleHeader    *keyHdrPtr;    /* Hash key, part 2 */
  180.     register List_Links     *hashList;    /* Bucket list indexed by Hash*/
  181. {
  182.     register FslclHashEntry *hashEntryPtr;
  183.  
  184.     LIST_FORALL(hashList, (List_Links *) hashEntryPtr) {
  185.     if ((strcmp(hashEntryPtr->keyName, string) == 0) &&
  186.         (hashEntryPtr->keyHdrPtr == keyHdrPtr)) {
  187.         /*
  188.          * Move the entry to the front of the LRU list.
  189.          */
  190.         List_Move(&(hashEntryPtr->lru.links),
  191.              LIST_ATFRONT(&(table->lruList)));
  192.         return(hashEntryPtr);
  193.     }
  194.     }
  195.     /* 
  196.      * The desired entry isn't there 
  197.      */
  198.  
  199.     return ((FslclHashEntry *) NIL);
  200. }
  201.  
  202. /*
  203.  *---------------------------------------------------------
  204.  *
  205.  * FslclHashLookOnly --
  206.  *
  207.  *     Searches a hash table for an entry corresponding to the string
  208.  *    and parent file.
  209.  *
  210.  * Results:
  211.  *    The return value is a pointer to the entry for string,
  212.  *    if string was present in the table.  If string was not
  213.  *    present, NIL is returned.
  214.  *
  215.  * Side Effects:
  216.  *    None.
  217.  *
  218.  *---------------------------------------------------------
  219.  */
  220.  
  221. ENTRY FslclHashEntry *
  222. FslclHashLookOnly(table, string, keyHdrPtr)
  223.     register FslclHashTable *table;        /* Hash table to search. */
  224.     char        *string;        /* Hash key, part 1. */
  225.     Fs_HandleHeader    *keyHdrPtr;        /* Hash key, part 2. */
  226. {
  227.     FslclHashEntry *hashEntryPtr;
  228.  
  229.     LOCK_MONITOR;
  230.     fs_Stats.nameCache.accesses++;
  231.     hashEntryPtr = ChainSearch(table, string, keyHdrPtr,
  232.           &(table->table[Hash(table, string, keyHdrPtr)].list));
  233.     if (hashEntryPtr != (FslclHashEntry  *) NIL) {
  234.     fs_Stats.nameCache.hits++;
  235.     }
  236.  
  237.     UNLOCK_MONITOR;
  238.     return(hashEntryPtr);
  239. }
  240.  
  241.  
  242. /*
  243.  *---------------------------------------------------------
  244.  *
  245.  * FsHashFind --
  246.  *
  247.  *    Searches a hash table for an entry corresponding to
  248.  *    key.  If no entry is found, then one is created.
  249.  *
  250.  * Results:
  251.  *    The return value is a pointer to the entry for string.
  252.  *    If the entry is a new one, then the pointer field is
  253.  *    zero.
  254.  *
  255.  *    Side Effects:
  256.  *    Memory is allocated, and the hash buckets may be modified.
  257.  *---------------------------------------------------------
  258.  */
  259.  
  260. ENTRY FslclHashEntry *
  261. FslclHashInsert(table, string, keyHdrPtr, hdrPtr)
  262.     register FslclHashTable    *table;        /* Hash table to search. */
  263.     register    char        *string;    /* Hash key, part 1 */
  264.     Fs_HandleHeader        *keyHdrPtr;    /* Hash key, part 2 */
  265.     Fs_HandleHeader        *hdrPtr;    /* Value */
  266. {
  267.     register     FslclHashBucket     *bucketPtr;
  268.     register     FslclHashEntry    *hashEntryPtr;
  269.     register    List_Links    *lruLinkPtr;
  270.  
  271.     LOCK_MONITOR;
  272.  
  273.     bucketPtr = &(table->table[Hash(table, string, keyHdrPtr)]);
  274.     hashEntryPtr = ChainSearch(table, string, keyHdrPtr,
  275.                     &(bucketPtr->list));
  276.  
  277.     if (hashEntryPtr != (FslclHashEntry *) NIL) {
  278.     UNLOCK_MONITOR;
  279.     return(hashEntryPtr);
  280.     }
  281.  
  282.     /* 
  283.      * See if we have to do LRU replacement before adding another entry.
  284.      */
  285.  
  286.     if (table->numEntries >= table->size) {
  287.     fs_Stats.nameCache.replacements++;
  288.     lruLinkPtr = LIST_ATREAR(&(table->lruList));
  289.     hashEntryPtr = ((struct FsLruList *)lruLinkPtr)->entryPtr;
  290.     Fsutil_HandleDecRefCount(hashEntryPtr->hdrPtr);
  291.     Fsutil_HandleDecRefCount(hashEntryPtr->keyHdrPtr);
  292.     List_Remove((List_Links *)hashEntryPtr);
  293.     List_Remove(&(hashEntryPtr->lru.links));
  294.     free((Address)hashEntryPtr);
  295.     } else {
  296.     table->numEntries += 1;
  297.     }
  298.  
  299.     /*
  300.      * Not there, we have to allocate.  If the string is longer than 3
  301.      * bytes, then we have to allocate extra space in the entry.
  302.      */
  303.  
  304.     hashEntryPtr = (FslclHashEntry *) malloc(sizeof(FslclHashEntry) + 
  305.             strlen(string) - 3);
  306.     (void)strcpy(hashEntryPtr->keyName, string);
  307.     hashEntryPtr->keyHdrPtr = keyHdrPtr;
  308.     hashEntryPtr->hdrPtr = hdrPtr;
  309.     hashEntryPtr->bucketPtr = bucketPtr;
  310.     List_Insert((List_Links *) hashEntryPtr, LIST_ATFRONT(&(bucketPtr->list)));
  311.     hashEntryPtr->lru.entryPtr = hashEntryPtr;
  312.     List_Insert(&(hashEntryPtr->lru.links), LIST_ATFRONT(&(table->lruList)));
  313.     /*
  314.      * Increment the reference count on the handle since we now have it
  315.      * in the name cache.
  316.      */
  317.     Fsutil_HandleIncRefCount(hdrPtr, 1);
  318.     Fsutil_HandleIncRefCount(keyHdrPtr, 1);
  319.     UNLOCK_MONITOR;
  320.  
  321.     return(hashEntryPtr);
  322. }
  323.  
  324. /*
  325.  *---------------------------------------------------------
  326.  *
  327.  * FslclHashDelete --
  328.  *
  329.  *     Search the hash table for an entry corresponding to the string
  330.  *    and parent file and then delete it if it is there.
  331.  *
  332.  * Results:
  333.  *    None.
  334.  *
  335.  * Side Effects:
  336.  *    Hash chain that entry lives is modified and memory is freed.
  337.  *
  338.  *---------------------------------------------------------
  339.  */
  340.  
  341. void
  342. FslclHashDelete(table, string, keyHdrPtr)
  343.     register FslclHashTable *table;    /* Hash table to search. */
  344.     char         *string;        /* Hash key, part 1. */
  345.     Fs_HandleHeader     *keyHdrPtr;        /* Hash key, part 2. */
  346. {
  347.     FslclHashEntry *hashEntryPtr;
  348.  
  349.     LOCK_MONITOR;
  350.  
  351.     fs_Stats.nameCache.accesses++;
  352.     hashEntryPtr = ChainSearch(table, string, keyHdrPtr,
  353.           &(table->table[Hash(table, string, keyHdrPtr)].list));
  354.     if (hashEntryPtr != (FslclHashEntry  *) NIL) {
  355.     /*
  356.      * Release the two handles referenced by the name cache entry.
  357.      * This is called when deleting the file, at which point both
  358.      * the parent (keyHdrPtr) and the file itself (hdrPtr) are locked.
  359.      */
  360.     Fsutil_HandleDecRefCount(hashEntryPtr->hdrPtr);
  361.     Fsutil_HandleDecRefCount(hashEntryPtr->keyHdrPtr);
  362.     List_Remove((List_Links *)hashEntryPtr);
  363.     List_Remove(&(hashEntryPtr->lru.links));
  364.     free((Address)hashEntryPtr);
  365.     table->numEntries--;
  366.     }
  367.  
  368.     UNLOCK_MONITOR;
  369. }
  370.  
  371.  
  372. /*
  373.  *---------------------------------------------------------
  374.  *
  375.  * FsRebuildTable --
  376.  *    This local routine makes a new hash table that
  377.  *    is larger than the old one.
  378.  *
  379.  * Results:    
  380.  *     None.
  381.  *
  382.  * Side Effects:
  383.  *    The entire hash table is moved, so any bucket numbers
  384.  *    from the old table are invalid.
  385.  *
  386.  *---------------------------------------------------------
  387.  */
  388. #ifdef notdef
  389. static void
  390. FsRebuildTable(table)
  391.     register    FslclHashTable     *table;        /* Table to be enlarged. */
  392. {
  393.     register    FslclHashBucket    *oldTable;
  394.     register    FslclHashEntry      *hashEntryPtr;
  395.     register    int         oldSize;
  396.     int              bucket;
  397.     FslclHashBucket        *saveTable;
  398.     FslclHashBucket        *bucketPtr;
  399.     Fs_HandleHeader        *keyHdrPtr;
  400.     int                 version;
  401.  
  402.     LOCK_MONITOR;
  403.  
  404.     saveTable = table->table;
  405.     oldSize = table->size;
  406.  
  407.     /* 
  408.      * Build a new table 4 times as large as the old one. 
  409.      */
  410.  
  411.     HashInit(table, table->size * 4);
  412.  
  413.     for (oldTable = saveTable; oldSize > 0; oldSize--, oldTable++) {
  414.     while (!List_IsEmpty(&(oldTable->list))) {
  415.         hashEntryPtr = (FslclHashEntry *) List_First(&(oldTable->list));
  416.         List_Remove((List_Links *) hashEntryPtr);
  417.         List_Remove(&(hashEntryPtr->lru.links));
  418.         keyHdrPtr = hashEntryPtr->keyHdrPtr;
  419.         bucket = Hash(table, hashEntryPtr->keyName, keyHdrPtr);
  420.         bucketPtr = &(table->table[bucket]);
  421.         List_Insert((List_Links *) hashEntryPtr, 
  422.         LIST_ATFRONT(&(bucketPtr->list)));
  423.         List_Insert(&(hashEntryPtr->lru.links),
  424.         LIST_ATFRONT(&(table->lruList)));
  425.         hashEntryPtr->bucketPtr = bucketPtr;
  426.         table->numEntries++;
  427.     }
  428.     }
  429.  
  430.     free((Address) saveTable);
  431.  
  432.     UNLOCK_MONITOR;
  433. }
  434. #endif notdef
  435.  
  436. /*
  437.  *---------------------------------------------------------
  438.  *
  439.  * FsHashStats --
  440.  *    This routine merely prints statistics about the
  441.  *    current bucket situation.
  442.  *
  443.  * Results:    
  444.  *    None.
  445.  *
  446.  * Side Effects:    
  447.  *    Junk gets printed.
  448.  *
  449.  *---------------------------------------------------------
  450.  */
  451.  
  452. void
  453. FslclNameHashStats()
  454. {
  455.     FslclHashTable *table = fslclNameTablePtr;
  456.     int count[10], overflow, i, j;
  457.     FslclHashEntry     *hashEntryPtr;
  458.     List_Links    *hashList;
  459.  
  460.     if (table == (FslclHashTable *)NULL || table == (FslclHashTable *)NIL) {
  461.     return;
  462.     }
  463.     for (i=0; i<10; i++) {
  464.     count[i] = 0;
  465.     }
  466.     overflow = 0;
  467.     for (i = 0; i < table->size; i++) {
  468.     j = 0;
  469.     hashList = &(table->table[i].list);
  470.     LIST_FORALL(hashList, (List_Links *) hashEntryPtr) {
  471.         j++;
  472.     }
  473.     if (j < 10) {
  474.         count[j]++;
  475.     } else {
  476.         overflow++;
  477.     }
  478.     }
  479.  
  480.     printf("FS Name Hash Table, %d entries in %d buckets\n", 
  481.         table->numEntries, table->size);
  482.     for (i = 0;  i < 10; i++) {
  483.     printf("%d buckets with %d entries\n", count[i], i);
  484.     }
  485.     printf("%d buckets with > 9 entries\n", overflow);
  486. }
  487.